package com.engine.core.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.engine.core.gen.ParamOption;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.core.env.Environment;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Utils extends org.apache.commons.beanutils.ConvertUtils {

    static Environment environment;

    public static final Map<String,Class<?>> stringClassMap=new HashMap<String,Class<?>>(){{
          this.put("string",String.class);
          this.put("int",Integer.class);
          this.put("date", Date.class);
          this.put("short", Short.class);
          this.put("double", Double.class);
          this.put("datetime", Timestamp.class);
          this.put("long", Long.class);
          this.put("short", Short.class);
    }};

    public static final String urlDecode(String val, ParamOption paramOption){
           if(StringUtils.isBlank(val)){
               return "";
           }else{
               if(val.indexOf("%")>0){
                   try{
                      return URLDecoder.decode(val,"utf-8");
                   }catch (Exception e){
                   }
               }
           }
           return val;
    }

    public static final String nullDefault(String val,String defaultV){
         return StringUtils.isBlank(val)?defaultV:val;
    }

    public static final boolean getBoolean(Object val,boolean def){
        try{
            if(Boolean.class.isInstance(val)){
                return (Boolean)val;
            }else if(val==null){
                return def;
            }else{
                return Boolean.parseBoolean(String.valueOf(val));
            }
        }catch (Exception e){

        }
        return def;
    }

    public static final int getInt(Object val,Integer def){
        try{
            if(Number.class.isInstance(val)){
                return ((Number)val).intValue();
            }else{
                return Integer.parseInt(String.valueOf(val));
            }
        }catch (Exception e){

        }
        return def;
    }

    public static final JSON getJSON(String jsonStr){
           if(JSON.isValidObject(jsonStr)){
               return JSON.parseObject(jsonStr, Feature.OrderedField);
           }else if(JSON.isValidArray(jsonStr)){
               return JSON.parseArray(jsonStr,Feature.OrderedField);
           }else{
               return null;
           }
    }

    public static final String getArrayStr(List<String> columns){
        JSONArray ja=new JSONArray();
        for (int i = 0; i < columns.size(); i++) {
            ja.add(columns.get(i));
        }
        return ja.toJSONString();
    }



    public static final String nullDefault(String val){
        return StringUtils.isBlank(val)?"":val;
    }

    public static void main(String[] args) {
        try {
            System.out.println(URLEncoder.encode("request_url is not null and response_code=500","utf-8"));
            System.out.println(URLEncoder.encode("response_code,request_url","utf-8"));

            System.out.println(urlDecode("1232%25",null));
            System.out.println(URLDecoder.decode("%E7%8E%8B%E4%BF%8A","utf-8"));

            System.out.println(URLDecoder.decode("request_url%20is%20not%20null%20and%20response_code%3D500","utf-8"));

            Object objs=Utils.convertValueOrList("123,456,789","Integer",null);
            System.out.println(objs.getClass().isArray());
            Object obj[]=(Object[]) objs;
            System.out.println(Array.get(obj,0));
            System.out.println(Array.getLength(obj));

            String ss="{\n" +
                    "        \"where\":[{\n" +
                    "                    \"column\":\"id\",\n" +
                    "                    \"qtype\":\"eq\"\n" +
                    "                },{\n" +
                    "                    \"column\":\"resource_remark\",\n" +
                    "\"paramName\":\"resource_remark1\",\n" +
                    "                    \"value\":\"代码%\",\n" +
                    "                    \"qtype\":\"like\"\n" +
                    "                },{\n" +
                    "                    \"qtype\":\"or\",\n" +
                    "                    \"children\":[{\n" +
                    "                            \"column\":\"id\",\n" +
                    "                            \"paramName\":\"aid\",\n" +
                    "                            \"qtype\":\"in\"\n" +
                    "                        },{\n" +
                    "                            \"column\":\"id\",\n" +
                    "                            \"paramName\":\"bid\",\n" +
                    "                            \"qtype\":\"between\"\n" +
                    "                        }\n" +
                    "                   ]\n" +
                    "                }],\n" +
                    "        \"resId\":\"19\"\n" +
                    "}";

            System.out.println(JSONObject.parseObject(ss));

//            System.out.println(buildWhere(JSONObject.parseObject(ss),conditionFun));

//            System.out.println(URLDecoder.decode("1232%","utf-8"));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }




    public static  final <T> List<T> convertListByStr(String s,String split,Class<T> classz){
          String[] arr=s.split(split);
          List<T> list=new ArrayList<>();
          for (int i = 0; i < arr.length; i++) {
              list.add((T)Utils.convert(arr[i],classz));
          }
          return list;
    }


    public static  final <T> List<T> convertListByStr(String s,Class<T> classz){
        return convertListByStr(s,",",classz);
    }

    public static  final <T> T[] convertArrayByStr(String s, Class<T> classz){
         List<T> datas=convertListByStr(s,",",classz);
         return datas.toArray((T[])Array.newInstance(classz,datas.size()));
    }


    public static Object convertValueOrList(String source,String typeName,String ...format) throws Exception{
        if(source.contains(",")){
            String[] values=source.split(",");
            Object[] obj=new Object[values.length];
            for (int i = 0; i < values.length; i++) {
                obj[i]=convert(values[i],typeName,format);
            }
            return obj;
        }else{
            return convert(source,typeName,format);
        }
    }

    public static Object convertValues(String[] source,String typeName,String ...format) throws Exception{
        if(source.length>1){
            List<Object> dataArr=new ArrayList<>();
            for (int i = 0; i < source.length; i++) {
                dataArr.add(convert(source[i],typeName,format));
            }
            return dataArr;
        }else{
            return convert(source[0],typeName,format);
        }
    }

    public static String wrap(String source){
        return ","+source+",";
    }


    public static Object convert(String source,String typeName,String ...format) throws Exception{
          Class classz=stringClassMap.get(typeName);
          if(classz==null){
              try {
                  classz=Class.forName("java.lang."+typeName);
              } catch (ClassNotFoundException e) {
              }
              try {
                  classz=Class.forName("java.util."+typeName);
              } catch (ClassNotFoundException e) {
              }

              try {
                  classz=Class.forName("java.sql."+typeName);
              } catch (ClassNotFoundException e) {
              }
          }
          if(classz==null){
               throw new ClassNotFoundException(String.format("typeName:%s is not support",typeName));
          }
          if(Number.class.isAssignableFrom(classz) && NumberUtils.isCreatable(source)){
              try {
                  return convert(source,classz);
              } catch (Exception e) {
                  throw new ClassNotFoundException(String.format("typeName:%s,value:%s couvert fail",typeName,source));
              }
          }else if(Date.class.isAssignableFrom(classz)){
               if(NumberUtils.isCreatable(source)){
                   return new Date(Long.parseLong(source));
               }else if(!NumberUtils.isCreatable(source) && format==null){
                   return DateUtils.parseDate(source);
               }else if(!NumberUtils.isCreatable(source) && format!=null && format.length>0){
                   return DateUtils.parseDate(source,format);
               }
          }else{
              return convert(source,classz);
          }
          throw new ClassNotFoundException(String.format("typeName:%s,value:%s couvert fail",typeName,source));
    }


    public static Object convert(String source,Class classz,String ...format) throws Exception{
        if(Number.class.isAssignableFrom(classz) && NumberUtils.isCreatable(source)){
            try {
                return convert(source,classz);
            } catch (Exception e) {
                throw new ClassNotFoundException(String.format("typeName:%s,value:%s couvert fail",classz.getName(),source));
            }
        }else if(Date.class.isAssignableFrom(classz)){
            Date d=null;
            if(NumberUtils.isCreatable(source)){
                d= new Date(Long.parseLong(source));
            }else if(!NumberUtils.isCreatable(source) && format==null){
                d= DateUtils.parseDate(source);
            }else if(!NumberUtils.isCreatable(source) && format!=null && format.length>0){
                d= DateUtils.parseDate(source,format);
            }

            if(classz.equals(Timestamp.class)){
                return new Timestamp(d.getTime());
            }
            return d;
        }
        return convert(source,classz);
    }

    public static String getErrorInfoFromException(Exception e) {
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            sw.close();
            pw.close();
            return "\r\n" + sw.toString() + "\r\n";
        } catch (Exception e2) {
            return "ErrorInfoFromException";
        }
    }

    public static String buildWhere(JSONObject root, Function<JSONObject,String> conditionFun){
        StringBuilder wherebuilder=new StringBuilder();
        JSONArray children=root.getJSONArray("children");
        String type=root.getString("type");
        for(int a=0;a<children.size();a++){
             JSONObject item=children.getJSONObject(a);
             if(!Arrays.asList("or","and").contains(item.getString("type"))){
                 wherebuilder.append(conditionFun.apply(item));
             }else{
                  wherebuilder.append(" ( ");
                  wherebuilder.append(buildWhere(item,conditionFun));
                  wherebuilder.append(" ) ");
             }
             if(type.equalsIgnoreCase("or")){
                 wherebuilder.append(" or ");
             }else{
                 wherebuilder.append(" and ");
             }
        }
        if(type.equalsIgnoreCase("or")){
            wherebuilder.delete(wherebuilder.length()-3,wherebuilder.length());
        }else{
            wherebuilder.delete(wherebuilder.length()-4,wherebuilder.length());
        }
        return wherebuilder.toString();
    }

    public static String getInWhere(String oper,int len){
        StringBuilder where=new StringBuilder(oper);
        where.append("(");
        for (int i = 0; i < len; i++) {
            where.append("?");
            where.append(",");
        }
        where.deleteCharAt(where.length()-1);
        where.append(")");
        return where.toString();
    }


    public static String getInWhere(String oper,String[] exps,Map<String,String> columnAliasMap){
        StringBuilder where=new StringBuilder(oper);
        where.append("(");
        for (int i = 0; i < exps.length; i++) {
            where.append(exps[i]);
            where.append(",");
        }
        where.deleteCharAt(where.length()-1);
        where.append(")");
        return where.toString();
    }

    public static String getFunStr(String funStr,String paramAlias,Map<String,String> columnAliasMap){
        StringBuilder where=new StringBuilder(funStr);
        int idxwh=-1;
        idxwh=where.indexOf("?");
        int idx=0;
        while(idxwh>-1){
            where.replace(idxwh,idxwh+1,":"+paramAlias+"_"+idx);
            idxwh=where.indexOf("?");
            idx++;
        }
        return replaceColumnAlias(where.toString(),columnAliasMap);
    }


    public static String replaceColumnAlias(String source,Map<String,String> columnAliasMap){
        String pattern = "([A-z][A-z|0-9|_|#]+)";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(source);
        String ss=new String(source);
        while(m.find()){
            String group=m.group();
            ss=ss.replaceAll(group,getColumnAlias(group,columnAliasMap));
        }
        return ss;
    }

    public static String getColumnAlias(String column,Map<String,String> columnAliasMap){
        if( !columnAliasMap.containsKey(column)){
            return column;
        }else{
            return columnAliasMap.get(column)+"."+column;
        }
    }



}
